'    Copyright 2008 Jan Molnar <jan.molnar@abds.de>
'
'    This file is part of JCQ.

'    JCQ is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 2 of the License, or
'    (at your option) any later version.

'    JCQ is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.

'    You should have received a copy of the GNU General Public License
'    along with JCQ. If not, see <http://www.gnu.org/licenses/>.

Public Class Snac1306
    Inherits Snac

    Public Sub New()
        MyBase.New(&H13, &H6)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Throw New NotImplementedException
    End Function

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Throw New NotImplementedException
    End Function

    Private _LastChange As Date
    Public Property LastChange() As Date
        Get
            Return _LastChange
        End Get
        Set(ByVal value As Date)
            _LastChange = value
        End Set
    End Property


    Private _ItemCount As Integer
    Public Property ItemCount() As Integer
        Get
            Return _ItemCount
        End Get
        Set(ByVal value As Integer)
            _ItemCount = value
        End Set
    End Property


    Private _BuddyRecords As New List(Of SSIBuddyRecord)
    Public ReadOnly Property BuddyRecords() As List(Of SSIBuddyRecord)
        Get
            Return _BuddyRecords
        End Get
    End Property

    Private _GroupRecords As New List(Of SSIGroupRecord)
    Public ReadOnly Property GroupRecords() As List(Of SSIGroupRecord)
        Get
            Return _GroupRecords
        End Get
    End Property

    Private _PermitRecords As New List(Of SSIPermitRecord)
    Public ReadOnly Property PermitRecords() As List(Of SSIPermitRecord)
        Get
            Return _PermitRecords
        End Get
    End Property

    Private _IgnoreListRecords As New List(Of SSIIgnoreListRecord)
    Public ReadOnly Property IgnoreListRecords() As List(Of SSIIgnoreListRecord)
        Get
            Return _IgnoreListRecords
        End Get
    End Property

    Private _DenyRecords As New List(Of SSIDenyRecord)
    Public ReadOnly Property DenyRecords() As List(Of SSIDenyRecord)
        Get
            Return _DenyRecords
        End Get
    End Property

    Private _PermitDenySettings As New SSIPermitDenySettings
    Public ReadOnly Property PermitDenySettings() As SSIPermitDenySettings
        Get
            Return _PermitDenySettings
        End Get
    End Property

    Private _RosterImportTime As New SSIRosterImportTime
    Public ReadOnly Property RosterImportTime() As SSIRosterImportTime
        Get
            Return _RosterImportTime
        End Get
    End Property

    Private _BuddyIcon As SSIBuddyIcon
    Public ReadOnly Property BuddyIcon() As SSIBuddyIcon
        Get
            Return _BuddyIcon
        End Get
    End Property

    Private _MaxItemId As Integer
    Public ReadOnly Property MaxItemId() As Integer
        Get
            Return _MaxItemId
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Snac.SizeFixPart

        ' Version info (byte)
        index += 1

        Dim itemIndex As Integer

        itemCount = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        Do While itemIndex < itemCount
            Dim desc As SSIItemDescriptor = SSIItemDescriptor.GetDescriptor(index, data)

            Select Case desc.ItemType
                Case SSIItemType.BuddyRecord
                    Dim buddy As SSIBuddyRecord
                    buddy = New SSIBuddyRecord
                    buddy.Deserialize(data.GetRange(index, desc.TotalSize))
                    _BuddyRecords.Add(buddy)
                Case SSIItemType.GroupRecord
                    Dim group As SSIGroupRecord
                    group = New SSIGroupRecord
                    group.Deserialize(data.GetRange(index, desc.TotalSize))
                    _GroupRecords.Add(group)
                Case SSIItemType.PermitRecord
                    Dim permit As SSIPermitRecord
                    permit = New SSIPermitRecord
                    permit.Deserialize(data.GetRange(index, desc.TotalSize))
                    _PermitRecords.Add(permit)
                Case SSIItemType.DenyRecord
                    Dim deny As SSIDenyRecord
                    deny = New SSIDenyRecord
                    deny.Deserialize(data.GetRange(index, desc.TotalSize))
                    _DenyRecords.Add(deny)
                Case SSIItemType.IgnoreListRecord
                    Dim ignore As SSIIgnoreListRecord
                    ignore = New SSIIgnoreListRecord
                    ignore.Deserialize(data.GetRange(index, desc.TotalSize))
                    _IgnoreListRecords.Add(ignore)
                Case SSIItemType.PermitDenySettings
                    _PermitDenySettings.Deserialize(data.GetRange(index, desc.TotalSize))
                Case SSIItemType.RosterImportTime
                    _RosterImportTime.Deserialize(data.GetRange(index, desc.TotalSize))
                Case SSIItemType.OwnIconAvatarInfo
                    _BuddyIcon = New SSIBuddyIcon
                    _BuddyIcon.Deserialize(data.GetRange(index, desc.TotalSize))
                Case Else
                    Core.Kernel.Logger.Log("Snac1306", TraceEventType.Error, "Unsupported SSI item type: {0}", desc.ItemType)
            End Select

            index += desc.TotalSize
            itemIndex += 1

            _MaxItemId = Math.Max(desc.ItemId, MaxItemId)
        Loop

        _LastChange = ByteConverter.ToDateTimeFromUInt32FileStamp(data.GetRange(index, 4))
        index += 4

        Me.SetTotalSize(index)
    End Sub
End Class

Public Class SSIItemDescriptor

    Private _ItemName As String
    Public ReadOnly Property ItemName() As String
        Get
            Return _ItemName
        End Get
    End Property

    Private _GroupId As Integer
    Public ReadOnly Property GroupId() As Integer
        Get
            Return _GroupId
        End Get
    End Property

    Private _ItemId As Integer
    Public ReadOnly Property ItemId() As Integer
        Get
            Return _ItemId
        End Get
    End Property

    Private _ItemType As SSIItemType
    Public ReadOnly Property ItemType() As SSIItemType
        Get
            Return _ItemType
        End Get
    End Property

    Private _AdditionalDataIndex As Integer
    Public ReadOnly Property AdditionalDataIndex() As Integer
        Get
            Return _AdditionalDataIndex
        End Get
    End Property

    Public ReadOnly Property TotalSize() As Integer
        Get
            Return _DataSize + 2 + 2 + 2 + 2 + 2 + _ItemName.Length
        End Get
    End Property

    Private _DataSize As Integer
    Public ReadOnly Property DataSize() As Integer
        Get
            Return _DataSize
        End Get
    End Property

    Public Shared Function GetDescriptor(ByVal offset As Integer, ByVal data As List(Of Byte)) As SSIItemDescriptor
        Dim descriptor As SSIItemDescriptor = New SSIItemDescriptor
        descriptor.Deserialize(offset, data)
        Return descriptor
    End Function

    Private Sub Deserialize(ByVal offset As Integer, ByVal bytes As List(Of Byte))
        Dim data As List(Of Byte) = bytes.GetRange(offset, bytes.Count - offset)
        Dim index As Integer

        _ItemName = ByteConverter.ToStringFromUInt16Index(index, data)
        index += _ItemName.Length + 2

        _GroupId = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        _ItemId = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        _ItemType = DirectCast(CInt(ByteConverter.ToUInt16(data.GetRange(index, 2))), SSIItemType)
        index += 2

        _DataSize = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        _AdditionalDataIndex = offset + index
    End Sub
End Class

Public Enum SSIItemType
    BuddyRecord = &H0
    GroupRecord = &H1
    PermitRecord = &H2
    DenyRecord = &H3
    PermitDenySettings = &H4
    PresenceInfo = &H5
    IgnoreListRecord = &HE
    LastUpdateDate = &HF
    NonICQContact = &H10
    RosterImportTime = &H13
    OwnIconAvatarInfo = &H14
End Enum

Public MustInherit Class SSIRecord
    Implements ISerializable

    Public Sub New(ByVal type As SSIItemType)
        _ItemType = type
    End Sub

    Private _ItemName As String
    Public Property ItemName() As String
        Get
            Return _ItemName
        End Get
        Set(ByVal value As String)
            If value = "143979279" Then Debugger.Break()
            _ItemName = value
        End Set
    End Property

    Private _GroupId As Integer
    Public Property GroupId() As Integer
        Get
            Return _GroupId
        End Get
        Set(ByVal value As Integer)
            _GroupId = value
        End Set
    End Property

    Private _ItemId As Integer
    Public Property ItemId() As Integer
        Get
            Return _ItemId
        End Get
        Set(ByVal value As Integer)
            _ItemId = value
        End Set
    End Property

    Private _ItemType As SSIItemType
    Public Property ItemType() As SSIItemType
        Get
            Return _ItemType
        End Get
        Set(ByVal value As SSIItemType)
            _ItemType = value
        End Set
    End Property

    Private _DataSize As Integer
    Public ReadOnly Property DataSize() As Integer Implements ISerializable.DataSize
        Get
            Return _DataSize
        End Get
    End Property

    Public ReadOnly Property TotalSize() As Integer Implements ISerializable.TotalSize
        Get
            Return SizeFixPart + DataSize
        End Get
    End Property

    Private _HasData As Boolean
    Public ReadOnly Property HasData() As Boolean Implements ISerializable.HasData
        Get
            Return _HasData
        End Get
    End Property

    Protected ReadOnly Property SizeFixPart() As Integer
        Get
            Return 2 + _ItemName.Length + 2 + 2 + 2 + 2
        End Get
    End Property

    Public MustOverride Function CalculateDataSize() As Integer Implements ISerializable.CalculateDataSize

    Public Function CalculateTotalSize() As Integer Implements ISerializable.CalculateTotalSize
        Return SizeFixPart + CalculateDataSize()
    End Function


    Public Overridable Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte)) Implements ISerializable.Deserialize
        Dim index As Integer

        _ItemName = ByteConverter.ToStringFromUInt16Index(index, data)
        index += _ItemName.Length + 2

        _GroupId = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        _ItemId = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        _ItemType = DirectCast(CInt(ByteConverter.ToUInt16(data.GetRange(index, 2))), SSIItemType)
        index += 2

        _DataSize = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2
    End Sub

    Public Overridable Function Serialize() As System.Collections.Generic.List(Of Byte) Implements ISerializable.Serialize
        Dim data As List(Of Byte) = New List(Of Byte)
        Dim dataSize As Integer

        dataSize = CalculateDataSize()

        data.AddRange(ByteConverter.GetBytes(CUShort(_ItemName.Length)))
        data.AddRange(ByteConverter.GetBytes(_ItemName))
        data.AddRange(ByteConverter.GetBytes(CUShort(_GroupId)))
        data.AddRange(ByteConverter.GetBytes(CUShort(_ItemId)))
        data.AddRange(ByteConverter.GetBytes(CUShort(_ItemType)))
        data.AddRange(ByteConverter.GetBytes(CUShort(dataSize)))

        Return data
    End Function

End Class

Public Class SSIBuddyRecord
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.BuddyRecord)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return 0
    End Function

    Private _AwaitingAuthorization As Boolean
    Public Property AwaitingAuthorization() As Boolean
        Get
            Return _AwaitingAuthorization
        End Get
        Set(ByVal value As Boolean)
            _AwaitingAuthorization = value
        End Set
    End Property

    Private _LocalScreenName As New TlvLocalScreenName
    Public ReadOnly Property LocalScreenName() As TlvLocalScreenName
        Get
            Return _LocalScreenName
        End Get
    End Property

    Private _LocalEmailAddress As New TlvLocalEmailAddress
    Public ReadOnly Property LocalEmailAddress() As TlvLocalEmailAddress
        Get
            Return _LocalEmailAddress
        End Get
    End Property

    Private _LocalSmsNumber As New TlvLocalSmsNumber
    Public ReadOnly Property LocalSmsNumber() As TlvLocalSmsNumber
        Get
            Return _LocalSmsNumber
        End Get
    End Property

    Private _Comment As New TlvBuddyCommentField
    Public ReadOnly Property Comment() As TlvBuddyCommentField
        Get
            Return _Comment
        End Get
    End Property

    Private _PersonalAlerts As New TlvPersonalBuddyAlerts
    Public ReadOnly Property PersonalAlerts() As TlvPersonalBuddyAlerts
        Get
            Return _PersonalAlerts
        End Get
    End Property

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Return MyBase.Serialize
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Me.SizeFixPart

        Do While index < data.Count
            Dim desc As TlvDescriptor = TlvDescriptor.GetDescriptor(index, data)

            Select Case desc.TypeId
                Case &H66
                    _AwaitingAuthorization = True
                Case &H131
                    _LocalScreenName.Deserialize(data.GetRange(index, desc.TotalSize))
                Case &H137
                    _LocalEmailAddress.Deserialize(data.GetRange(index, desc.TotalSize))
                Case &H13A
                    _LocalSmsNumber.Deserialize(data.GetRange(index, desc.TotalSize))
                Case &H13C
                    _Comment.Deserialize(data.GetRange(index, desc.TotalSize))
                Case &H13D
                    _PersonalAlerts.Deserialize(data.GetRange(index, desc.TotalSize))
            End Select

            index += desc.TotalSize
        Loop
    End Sub
End Class

Public Enum PrivacySetting As Byte
    AllowAllUsersToSeeMe = 1
    BlockAllUsersFromSeeingMe = 2
    AllowOnlyUsersInPermitList = 3
    BlockOnlyUsersInDenyList = 4
    AllowOnlyUsersInBuddyList = 5
End Enum

Public Class TlvPrivacySetting
    Inherits Tlv

    Public Sub New()
        MyBase.New(&HCA)
    End Sub

    Private _PrivacySetting As PrivacySetting
    Public Property PrivacySetting() As PrivacySetting
        Get
            Return _PrivacySetting
        End Get
        Set(ByVal value As PrivacySetting)
            _PrivacySetting = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return 1
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _PrivacySetting = DirectCast(data(index), PrivacySetting)
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()
        data.Add(CByte(_PrivacySetting))
        Return data
    End Function
End Class

Public Class TlvAllowOtherToSee
    Inherits Tlv

    Public Sub New()
        MyBase.New(&HCC)
    End Sub

    Private _AllowOtherToSeeSetting As AllowOtherToSeeSetting
    Public Property AllowOtherToSeeSetting() As AllowOtherToSeeSetting
        Get
            Return _AllowOtherToSeeSetting
        End Get
        Set(ByVal value As AllowOtherToSeeSetting)
            _AllowOtherToSeeSetting = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return 4
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _AllowOtherToSeeSetting = DirectCast(ByteConverter.ToUInt32(data.GetRange(index, 4)), AllowOtherToSeeSetting)
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()
        data.AddRange(ByteConverter.GetBytes(CUInt(_AllowOtherToSeeSetting)))
        Return data
    End Function
End Class

<Flags()> Public Enum AllowOtherToSeeSetting As UInteger
    DoNotAllowOthersToSeeThatIAmUsingAWirelessDevice = &H2
    AllowOthersToSeeMyIdleTime = &H400
    AllowOthersToSeeThatIAmTypingAResponse = &H400000
End Enum

Public Class TlvBuddyListImportTime
    Inherits Tlv

    Public Sub New()
        MyBase.New(&HD4)
    End Sub

    Private _ImportTime As Date
    Public Property ImportTime() As Date
        Get
            Return _ImportTime
        End Get
        Set(ByVal value As Date)
            _ImportTime = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return 4
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _ImportTime = ByteConverter.ToDateTimeFromUInt32FileStamp(data.GetRange(index, 4))
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()
        data.AddRange(ByteConverter.GetBytesForUInt32Date(_ImportTime))
        Return data
    End Function
End Class

Public Class TlvLocalScreenName
    Inherits Tlv

    Public Sub New()
        MyBase.New(&H131)
    End Sub

    Private _LocalScreenName As String
    Public Property LocalScreenName() As String
        Get
            Return _LocalScreenName
        End Get
        Set(ByVal value As String)
            _LocalScreenName = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        If String.IsNullOrEmpty(_LocalScreenName) Then Return 0

        Return _LocalScreenName.Length
    End Function

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()

        If Not String.IsNullOrEmpty(_LocalScreenName) Then
            data.AddRange(ByteConverter.GetBytes(_LocalScreenName))
        End If

        Return data
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _LocalScreenName = ByteConverter.ToString(data.GetRange(index, DataSize))
    End Sub
End Class

Public Class TlvLocalEmailAddress
    Inherits Tlv

    Public Sub New()
        MyBase.New(&H137)
    End Sub

    Private _LocalEmailAddress As String
    Public Property LocalEmailAddress() As String
        Get
            Return _LocalEmailAddress
        End Get
        Set(ByVal value As String)
            _LocalEmailAddress = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return _LocalEmailAddress.Length
    End Function

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()

        data.AddRange(ByteConverter.GetBytes(_LocalEmailAddress))

        Return data
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _LocalEmailAddress = ByteConverter.ToString(data.GetRange(index, DataSize))
    End Sub
End Class

Public Class TlvLocalSmsNumber
    Inherits Tlv

    Public Sub New()
        MyBase.New(&H13A)
    End Sub

    Private _LocalSmsNumber As String
    Public Property LocalSmsNumber() As String
        Get
            Return _LocalSmsNumber
        End Get
        Set(ByVal value As String)
            _LocalSmsNumber = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return _LocalSmsNumber.Length
    End Function

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()

        data.AddRange(ByteConverter.GetBytes(_LocalSmsNumber))

        Return data
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _LocalSmsNumber = ByteConverter.ToString(data.GetRange(index, DataSize))
    End Sub
End Class

Public Class TlvBuddyCommentField
    Inherits Tlv

    Public Sub New()
        MyBase.New(&H13C)
    End Sub

    Private _Comment As String
    Public Property Comment() As String
        Get
            Return _Comment
        End Get
        Set(ByVal value As String)
            _Comment = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return _Comment.Length
    End Function

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()

        data.AddRange(ByteConverter.GetBytes(_Comment))

        Return data
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _Comment = ByteConverter.ToString(data.GetRange(index, DataSize))
    End Sub
End Class

Public Class TlvPersonalBuddyAlerts
    Inherits Tlv

    Public Sub New()
        MyBase.New(&H13D)
    End Sub

    Private _AlertType As BuddyAlertType
    Public Property AlertType() As BuddyAlertType
        Get
            Return _AlertType
        End Get
        Set(ByVal value As BuddyAlertType)
            _AlertType = value
        End Set
    End Property


    Private _Alert As BuddyAlert
    Public Property Alert() As BuddyAlert
        Get
            Return _Alert
        End Get
        Set(ByVal value As BuddyAlert)
            _Alert = value
        End Set
    End Property

    Public Overrides Function CalculateDataSize() As Integer
        Return 2
    End Function

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()
        data.Add(_AlertType)
        data.Add(_Alert)
        Return data
    End Function

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        _AlertType = DirectCast(data(index), BuddyAlertType)
        _Alert = DirectCast(data(index + 1), BuddyAlert)
    End Sub
End Class

Public Enum BuddyAlertType As Byte
    PopUpWindow = &H1
    PlaySound = &H2
End Enum

Public Enum BuddyAlert As Byte
    WhenContactComesOnline = &H1
    WhenContactBecomesUnidle = &H2
    WhenContactReturnsFromAway = &H4
End Enum

Public Class SSIGroupRecord
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.GroupRecord)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return _InnerItems.TotalSize
    End Function

    Private _IsMasterGroup As Boolean
    Public Property IsMasterGroup() As Boolean
        Get
            Return _IsMasterGroup
        End Get
        Set(ByVal value As Boolean)
            _IsMasterGroup = value
        End Set
    End Property

    Private _InnerItems As New TlvSSIInnerItems
    Public ReadOnly Property InnerItems() As TlvSSIInnerItems
        Get
            Return _InnerItems
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Me.SizeFixPart

        If GroupId = 0 Then
            _IsMasterGroup = True
        End If

        Do While index < data.Count
            Dim desc As TlvDescriptor = TlvDescriptor.GetDescriptor(index, data)

            Select Case desc.TypeId
                Case &HC8
                    _InnerItems.Deserialize(data.GetRange(index, desc.TotalSize))
            End Select

            index += desc.TotalSize
        Loop
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()

        data.AddRange(_InnerItems.Serialize)

        Return data
    End Function
End Class

Public Class SSIRosterImportTime
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.RosterImportTime)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return _ImportTime.TotalSize
    End Function

    Private _ImportTime As New TlvBuddyListImportTime
    Public ReadOnly Property ImportTime() As TlvBuddyListImportTime
        Get
            Return _ImportTime
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Me.SizeFixPart

        Do While index < data.Count
            Dim desc As TlvDescriptor = TlvDescriptor.GetDescriptor(index, data)

            Select Case desc.TypeId
                Case &HD4
                    _ImportTime.Deserialize(data.GetRange(index, desc.TotalSize))
            End Select

            index += desc.TotalSize
        Loop
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Throw New NotImplementedException
    End Function
End Class

Public Class SSIPermitDenySettings
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.PermitDenySettings)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return _PrivacySetting.TotalSize + _AllowOthersToSee.TotalSize
    End Function

    Private _PrivacySetting As New TlvPrivacySetting
    Public ReadOnly Property PrivacySetting() As TlvPrivacySetting
        Get
            Return _PrivacySetting
        End Get
    End Property

    Private _AllowOthersToSee As New TlvAllowOtherToSee
    Public ReadOnly Property AllowOthersToSee() As TlvAllowOtherToSee
        Get
            Return _AllowOthersToSee
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Me.SizeFixPart

        Do While index < data.Count
            Dim desc As TlvDescriptor = TlvDescriptor.GetDescriptor(index, data)

            Select Case desc.TypeId
                Case &HCA
                    _PrivacySetting.Deserialize(data.GetRange(index, desc.TotalSize))
                Case &HCC
                    _AllowOthersToSee.Deserialize(data.GetRange(index, desc.TotalSize))
            End Select

            index += desc.TotalSize
        Loop
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Throw New NotImplementedException
    End Function
End Class

Public Class SSIPermitRecord
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.PermitRecord)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return 0
    End Function
End Class

Public Class SSIDenyRecord
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.DenyRecord)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return 0
    End Function
End Class

Public Class SSIIgnoreListRecord
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.IgnoreListRecord)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return 0
    End Function
End Class

Public Class TlvSSIInnerItems
    Inherits Tlv

    Public Sub New()
        MyBase.New(&HC8)
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return _InnerItems.Count * 2
    End Function

    Private _InnerItems As New List(Of Integer)
    Public ReadOnly Property InnerItems() As List(Of Integer)
        Get
            Return _InnerItems
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        Do While index < data.Count
            _InnerItems.Add(ByteConverter.ToUInt16(data.GetRange(index, 2)))

            index += 2
        Loop
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte) = MyBase.Serialize()

        For Each x As Integer In _InnerItems
            data.AddRange(ByteConverter.GetBytes(CUShort(x)))
        Next

        Return data
    End Function
End Class

Public Class SSIBuddyIcon
    Inherits SSIRecord

    Public Sub New()
        MyBase.New(SSIItemType.OwnIconAvatarInfo)
        ItemName = "1"
        'ItemId = &H4DC8
    End Sub

    Public Overrides Function CalculateDataSize() As Integer
        Return LocalScreenName.CalculateTotalSize + BuddyIcon.CalculateTotalSize
    End Function

    Private _BuddyIcon As New TlvBuddyIcon
    Public ReadOnly Property BuddyIcon() As TlvBuddyIcon
        Get
            Return _BuddyIcon
        End Get
    End Property

    Private _LocalScreenName As New TlvLocalScreenName
    Public ReadOnly Property LocalScreenName() As TlvLocalScreenName
        Get
            Return _LocalScreenName
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Me.SizeFixPart

        Do While index < data.Count
            Dim desc As TlvDescriptor = TlvDescriptor.GetDescriptor(index, data)

            Select Case desc.TypeId
                Case &HD5
                    _BuddyIcon.Deserialize(data.GetRange(index, desc.TotalSize))
            End Select

            index += desc.TotalSize
        Loop
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte)

        data = MyBase.Serialize()

        data.AddRange(LocalScreenName.Serialize)

        data.AddRange(BuddyIcon.Serialize)

        Return data
    End Function
End Class

Public Class TlvBuddyIcon
    Inherits Tlv

    Public Sub New()
        MyBase.New(&HD5)
    End Sub
    
    Public Overrides Function CalculateDataSize() As Integer
        Return 2 + IconHash.Count
    End Function

    Private _IconHash As New List(Of Byte)
    Public ReadOnly Property IconHash() As List(Of Byte)
        Get
            Return _IconHash
        End Get
    End Property

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        MyBase.Deserialize(data)

        Dim index As Integer = Tlv.SizeFixPart

        Dim length As Integer = ByteConverter.ToUInt16(data.GetRange(index, 2))
        index += 2

        '_IconHash.AddRange(data.GetRange(index, length))
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte)

        data = MyBase.Serialize

        ' MD5 Hash Size
        data.AddRange(ByteConverter.GetBytes(CUShort(IconHash.Count)))

        ' MD5 Hash
        data.AddRange(IconHash)

        Return data
    End Function
End Class